using System;
using System.Web;
using CommunityServer;
using CommunityServer.Components;
using System.Collections;
using System.Collections.Specialized;
using System.IO;
using System.Security.Permissions;
using System.Xml;

namespace FourRoads.Links.Modules
{

	internal class RewriterUtils
	{
		#region RewriteUrl
		/// <summary>
		/// Rewrite's a URL using <b>HttpContext.RewriteUrl()</b>.
		/// </summary>
		/// <param name="context">The HttpContext object to rewrite the URL to.</param>
		/// <param name="sendToUrl">The URL to rewrite to.</param>
		internal static void RewriteUrl(HttpContext context, string sendToUrl)
		{
			string x, y;
			RewriteUrl(context, sendToUrl, out x, out y);
		}

		/// <summary>
		/// Rewrite's a URL using <b>HttpContext.RewriteUrl()</b>.
		/// </summary>
		/// <param name="context">The HttpContext object to rewrite the URL to.</param>
		/// <param name="sendToUrl">The URL to rewrite to.</param>
		/// <param name="sendToUrlLessQString">Returns the value of sendToUrl stripped of the querystring.</param>
		/// <param name="filePath">Returns the physical file path to the requested page.</param>
		internal static void RewriteUrl(HttpContext context, string sendToUrl, out string sendToUrlLessQString, out string filePath)
		{
			// see if we need to add any extra querystring information
			if (context.Request.QueryString.Count > 0)
			{
				if (sendToUrl.IndexOf('?') != -1)
					sendToUrl += "&" + context.Request.QueryString.ToString();
				else
					sendToUrl += "?" + context.Request.QueryString.ToString();
			}

			// first strip the querystring, if any
			string queryString = String.Empty;
			sendToUrlLessQString = sendToUrl;
			if (sendToUrl.IndexOf('?') > 0)
			{
				sendToUrlLessQString = sendToUrl.Substring(0, sendToUrl.IndexOf('?'));
				queryString = sendToUrl.Substring(sendToUrl.IndexOf('?') + 1);
			}

			// grab the file's physical path
			filePath = string.Empty;
			filePath = context.Server.MapPath(sendToUrlLessQString);

			// rewrite the path...
			context.RewritePath(sendToUrlLessQString, String.Empty, queryString);
			// NOTE!  The above RewritePath() overload is only supported in the .NET Framework 1.1
			// If you are using .NET Framework 1.0, use the below form instead:
			// context.RewritePath(sendToUrl);
		}
		#endregion

		/// <summary>
		/// Converts a URL into one that is usable on the requesting client.
		/// </summary>
		/// <remarks>Converts ~ to the requesting application path.  Mimics the behavior of the 
		/// <b>Control.ResolveUrl()</b> method, which is often used by control developers.</remarks>
		/// <param name="appPath">The application path.</param>
		/// <param name="url">The URL, which might contain ~.</param>
		/// <returns>A resolved URL.  If the input parameter <b>url</b> contains ~, it is replaced with the
		/// value of the <b>appPath</b> parameter.</returns>
		internal static string ResolveUrl(string appPath, string url)
		{
			if (url.Length == 0 || url[0] != '~')
				return url;		// there is no ~ in the first character position, just return the url
			else
			{
				if (url.Length == 1)
					return appPath;  // there is just the ~ in the URL, return the appPath
				if (url[1] == '/' || url[1] == '\\')
				{
					// url looks like ~/ or ~\
					if (appPath.Length > 1)
						return appPath + "/" + url.Substring(2);
					else
						return "/" + url.Substring(2);
				}
				else
				{
					// url looks like ~something
					if (appPath.Length > 1)
						return appPath + "/" + url.Substring(1);
					else
						return appPath + url.Substring(1);
				}
			}
		}
	}

	/// <summary>
	/// Summary description for HttpModule.
	/// </summary>
    [AspNetHostingPermission(SecurityAction.InheritanceDemand  , Level = AspNetHostingPermissionLevel.Medium)]
 	public sealed class LinksFriendlyName : IHttpModule 
	{
		public LinksFriendlyName()
		{

		}
	
		public void Dispose (  )
		{

		}

		static bool _UrlReWriteEnabled = false;
        static bool _Done = false;
#if !Fx1_1
        public bool IsReusable { get { return true; }  }
#endif
        public static bool UrlReWriteEnabled()
		{
            //Open the web.config file and parse it
            //looke for the Httpmodules section and then check the 1 the linkFreindlyname exists
            //2 that it is after CommunityServer module
            if (!_Done)
            {
                _UrlReWriteEnabled = false;
                bool foundCS = false;
                XmlDocument doc = new XmlDocument();
                doc.Load(HttpContext.Current.Server.MapPath("~\\web.config"));

                XmlNodeList modules = doc.SelectNodes("configuration/system.web/httpModules/add");

                foreach (XmlNode nd in modules)
                {

                    switch (nd.Attributes["name"].Value.ToLower())
                    {
                        case "communityserver":
                        {
                            foundCS = true;
                        }
                        break;
                        case "linksfriendlyname":
                        {
                            _UrlReWriteEnabled = foundCS;
                        }
                        break;
                    }
                }

                _Done = true;
            }
            return _UrlReWriteEnabled;
        }

		public void Init(HttpApplication application) 
		{
			if (UrlReWriteEnabled())
				application.BeginRequest += new EventHandler(application_BeginRequest);
		}

		private void application_BeginRequest(object sender, EventArgs e)
		{
			HttpApplication app = (HttpApplication) sender;
			LocationSet ls = SiteUrls.Instance ( ).LocationSet;

			if ( ls != null )
			{
				Location location =ls.FindLocationByName ( "resourceLinks" );
				if ( location != null )
				{
					if ( app.Request.Path.StartsWith ( location.Path ) )
					{
						///this is the coookie now all we need to do is work our way along
						if ( app.Request.QueryString["SectionID"] == null )
						{
							//We are requesting a url that we can re-write
							Rewrite ( app.Request.Path.Remove ( 0, location.Path.Length ), location.Path, app );
						}
					}
				}
			}
		}

        private int DeepSectionSearch(ref string[] pathParts, ref int pathIdx, ResLinkSection curSec)
		{
			foreach(ResLinkSection subSec in curSec.Sections)
			{
				if (subSec.FreindlySectionName == pathParts[pathIdx])
				{
					if (pathIdx == pathParts.Length-1)
						return subSec.SectionID;

					pathIdx ++;
					return DeepSectionSearch(ref pathParts , ref pathIdx , ResLinkSection.GetSection(subSec.SectionID));
				}
			}

			return -1;
		}

        private void Rewrite(string requestedPath, string root, System.Web.HttpApplication app)
		{
			//Some how we now need to convert from friendly path to
			//<root>/Section_A/Section_b/filename.aspx
			//<root>/filename.aspx?SectionID=n
			
			//Firstly trim off the file name part
			string fileName = "default.aspx";
			int lastSlash = -1;
			string justPath = requestedPath;

			if(Path.GetExtension(requestedPath) != string.Empty)
			{
				lastSlash = requestedPath.LastIndexOf("/");
				if (lastSlash != -1)
				{
					fileName =requestedPath.Substring(lastSlash + 1).ToLower();
					justPath =  requestedPath.Substring( 0 , lastSlash);
				}
			}

			//Nasty little hack
			if (fileName == "rss.aspx")
			{
				fileName = "rss.ashx";
			}

			//REmove the trailling slash
			justPath = justPath.TrimEnd ('/');

			//Firstly check to see of some one has recently visted the path that has been entered
			object sectionIDobj = CSCache.Get(ResLinkSection.CreateFriendlyNameCacheKey(justPath.ToLower()));
			int sectionID  = -1;
			if (sectionIDobj == null)
			{   //Do it the hard way this is painfull!!!
				string[] pathParts = justPath.ToLower().Split(new char[] {'/'});
				//start at the root section and move outwards
				int pathIdx=0;

				sectionID = DeepSectionSearch(ref pathParts , ref pathIdx , ResLinkSection.GetSection(-1));
			}
			else
			{
				sectionID = (int)sectionIDobj;
			}

			string sendToUrl = root + fileName;
			if (fileName.IndexOf("?") != -1)//Has got a query string 
			{
				sendToUrl += "&SectionID=" + sectionID.ToString();
			}
			else
			{
				sendToUrl += "?SectionID=" + sectionID.ToString();
			}

			RewriterUtils.RewriteUrl(app.Context, sendToUrl);

			//Re-build the context file to 
			CSContext.Create(app.Context);
			CSContext.Current.IsUrlReWritten = true;
			CSContext.Current.RewrittenUrlName = sendToUrl;
		}
	}
}
